package what.api;

import java.util.HashMap;

import org.apache.bcel.classfile.JavaClass;
import org.apache.bcel.classfile.Method;

public class ApiClass {

	public ApiPackage apiPackage;
	public String className;
	public HashMap<String, ApiMethod> methods = new HashMap<String, ApiMethod>();
	public int nMethods = 0;
	
	public ApiClass(ApiPackage apiPackage, String className) {
		this.apiPackage = apiPackage;
		this.className = className;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result
				+ ((className == null) ? 0 : className.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		ApiClass other = (ApiClass) obj;
		if (className == null) {
			if (other.className != null)
				return false;
		} else if (!className.equals(other.className))
			return false;
		return true;
	}

	public static ApiClass load(String api, ApiLog log) {
		int sep1 = api.indexOf('|');
		int sep2 = api.indexOf('|', sep1 + 1);
		String packageName = api.substring(0, sep1);
		ApiPackage apiPackage =log.createApiPackage(null, packageName);
		String className = api.substring(sep1+1, sep2);
		ApiClass apiClass = apiPackage.classes.get(className);
		if (apiClass == null) {
			apiClass = new ApiClass(apiPackage, className);
			apiPackage.classes.put(className, apiClass);
		}
		int sep = sep2;
		while (true) {
			sep1 = api.indexOf('{', sep + 1);
			if (sep1 == -1)
				break;
			sep2 = api.indexOf('}', sep1 + 1);
			if (sep2 == -1)
				throw new IllegalArgumentException();
			String methodName = api.substring(sep+1,sep1);
			String signatureName = api.substring(sep1+1, sep2);
			ApiMethod method =  apiClass.methods.get(methodName);
			if (method == null) {
				method = new ApiMethod(apiClass, methodName);
				apiClass.methods.put(methodName, method);
			}
			ApiSignature signature = method.signatures.get(signatureName);
			if (signature == null) {
				signature = new ApiSignature(method, signatureName);
				method.signatures.put(signatureName, signature);
			}
			sep = sep2;
		}
		return apiClass;
	}
	
	/**
	 * Format: package name | class name | public method1{signature}public
	 * method2{}... Returns null if class isn't public.
	 */
	public static String save(JavaClass javaClass) {
		StringBuffer result = new StringBuffer();
		if (!javaClass.isPublic())
			return null;
		result.append(javaClass.getPackageName());
		result.append('|');
		result.append(getSimpleClassName(javaClass.getClassName()));
		result.append('|');
		for (Method method : javaClass.getMethods()) {
			if (!method.isPublic())
				continue;
			result.append(method.getName());
			result.append('{');
			result.append(method.getSignature());
			result.append('}');
		}
		result.append("\r\n");
		return result.toString();
	}

	static String getSimpleClassName(String className) {
		int index = className.lastIndexOf('.');
		return index != -1 ? className.substring(index + 1) : className;
	}
}
